﻿//-----------------------------------------------------------------------
// <copyright file="TriangleRenderEngine.cs" company="Flaxen Geo">
//    Copyright (c) 2011, Michael P. Gerlek.  All rights reserved.
// </copyright>
//
// Redistribution and use in source and binary forms, with or without 
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright notice,
//   this list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright notice, 
//   this list of conditions and the following disclaimer in the documentation
//   and/or other materials provided with the distribution.
//
// * Neither the name of Flaxen Geo nor the names of its contributors may be 
//   used to endorse or promote products derived from this software without 
//   specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 
// THE POSSIBILITY OF SUCH DAMAGE.
//-----------------------------------------------------------------------

// Some of this code was derived in part from examples on the web and in the SlimDX examples,
// which had no explicit license or copyright claim.  Feel free to let me know if you want
// credit here; I (and the community) are indebted to your contributions.

namespace Flaxen.SlimDXControlLib.TriangleExample
{
    using System.Diagnostics;
    using SlimDX;
    using SlimDX.D3DCompiler;
    using SlimDX.Direct3D10;
    using SlimDX.DXGI;
    using Buffer = SlimDX.Direct3D10.Buffer;

    /// <summary>
    /// This is an example rendering engine which demonstrates a basic rendering operation,
    /// with time-based animation.  The Initialize() method is provided to implement the effect, 
    /// and Reinitialize() is not needed since nothing need change when the window size changes.
    /// </summary>
    public class TriangleRenderEngine : SimpleRenderEngine
    {
        private Stopwatch m_timer;
        private DataStream m_sampleStream;
        private InputLayout m_sampleLayout;
        private Buffer m_sampleVertices;
        private Effect m_sampleEffect;
        private bool m_invert;

        /// <summary>
        /// Initializes a new instance of the TriangleRenderEngine class.  It supports two styles of display, based on the invert parameter.
        /// </summary>
        /// <param name="invert">changes the style of the triangle displayed</param>
        public TriangleRenderEngine(bool invert)
        {
            m_invert = invert;

            m_timer = new Stopwatch();
            m_timer.Start();
        }

        /// <summary>
        /// Implements the rendering pipeline.
        /// </summary>
        public override void Render()
        {
            Device.OutputMerger.SetTargets(SampleDepthView, SampleRenderView);
            Device.Rasterizer.SetViewports(new Viewport(0, 0, WindowWidth, WindowHeight, 0.0f, 1.0f));

            Device.ClearDepthStencilView(SampleDepthView, DepthStencilClearFlags.Depth | DepthStencilClearFlags.Stencil, 1.0f, 0);

            // set c to be in the range [0..1] based on current tick
            float c = ((float)(m_timer.ElapsedMilliseconds % 1000)) / 1000.0f;
            if (m_invert)
            {
                c = 1.0f - c;
            }

            Device.ClearRenderTargetView(SampleRenderView, new SlimDX.Color4(1.0f, c, c, c));

            Device.InputAssembler.SetInputLayout(m_sampleLayout);
            Device.InputAssembler.SetPrimitiveTopology(PrimitiveTopology.TriangleList);
            Device.InputAssembler.SetVertexBuffers(0, new VertexBufferBinding(m_sampleVertices, 32, 0));

            EffectTechnique technique = m_sampleEffect.GetTechniqueByIndex(0);
            EffectPass pass = technique.GetPassByIndex(0);

            for (int i = 0; i < technique.Description.PassCount; ++i)
            {
                pass.Apply();
                Device.Draw(3, 0);
            }

            Device.Flush();
        }

        /// <summary>
        /// Implements the creation of the effect and the sets up the vertices.
        /// </summary>
        /// <param name="control">the associated SlimDXControl object</param>
        public override void Initialize(SlimDXControl control)
        {
            base.Initialize(control);

            m_sampleEffect = Effect.FromFile(Device, "MiniTri.fx", "fx_4_0", ShaderFlags.None, EffectFlags.None, null, null);
            EffectTechnique technique = m_sampleEffect.GetTechniqueByIndex(0);
            EffectPass pass = technique.GetPassByIndex(0);
            InputElement[] inputElements = new[] 
                {
                    new InputElement("POSITION", 0, Format.R32G32B32A32_Float, 0, 0),
                    new InputElement("COLOR", 0, Format.R32G32B32A32_Float, 16, 0) 
                };
            m_sampleLayout = new InputLayout(Device, pass.Description.Signature, inputElements);

            m_sampleStream = new DataStream(3 * 32, true, true);
            m_sampleStream.WriteRange(
                new[] 
                {
                    new Vector4(0.0f, 0.5f, 0.5f, 1.0f), new Vector4(1.0f, 0.0f, 0.0f, 1.0f),
                    new Vector4(0.5f, -0.5f, 0.5f, 1.0f), new Vector4(0.0f, 1.0f, 0.0f, 1.0f),
                    new Vector4(-0.5f, -0.5f, 0.5f, 1.0f), new Vector4(0.0f, 0.0f, 1.0f, 1.0f)
                });

            m_sampleStream.Position = 0;

            BufferDescription bufferDesc = new BufferDescription()
            {
                BindFlags = BindFlags.VertexBuffer,
                CpuAccessFlags = CpuAccessFlags.None,
                OptionFlags = ResourceOptionFlags.None,
                SizeInBytes = 3 * 32,
                Usage = ResourceUsage.Default
            };
            m_sampleVertices = new Buffer(Device, m_sampleStream, bufferDesc);
            Device.Flush();
        }

        /// <summary>
        /// Disposes of our managed resources.
        /// </summary>
        protected override void DisposeManaged()
        {
            if (m_sampleVertices != null)
            {
                m_sampleVertices.Dispose();
                m_sampleVertices = null;
            }

            if (m_sampleLayout != null)
            {
                m_sampleLayout.Dispose();
                m_sampleLayout = null;
            }

            if (m_sampleEffect != null)
            {
                m_sampleEffect.Dispose();
                m_sampleEffect = null;
            }

            if (m_sampleStream != null)
            {
                m_sampleStream.Dispose();
                m_sampleStream = null;
            }

            if (SharedTexture != null)
            {
                SharedTexture.Dispose();
                SharedTexture = null;
            }

            base.DisposeManaged();

            return;
        }
    }
}
